<?php    
    class API {
        const SESSIONID = "sessionid";
        const VIEW      = "view";
        
        /**
         * Palautta URL polun rajapintaan.
         *
         * @return  string
         */
        private static function _getAPIUrl() {
            static $url = null;
            
            if (!isset($url)) {
                $url = config("API","url");
                if (!$url) {
                    if (isset($_SERVER["HTTPS"])) {
                        $url = "https";
                    } else {
                        $url = "http";
                    }
                    
                    $url .= "://{$_SERVER["HTTP_HOST"]}";
                    foreach (explode("/",$_SERVER["REQUEST_URI"]) as $part) {
                        if ($part == "UI") {
                            break;
                        }
                        if ($part) {
                            $url .= "/".$part;
                        }
                    }
                    $url .= "/API";
                }
                $url .= "/request";
            }
            
            return $url;
        }
        
        /**
        * Rajapintavastausten automaattinen käsittelijä joka laukaistaan ennen
        * JavaScriptin suorittamista.
        *
        * @param   string  $class      Kutsuttu luokka
        * @param   string  $function   Kutsuttu funktio
        * @param   array   $result     Kutsun vastaus
        * @return  array
        */
        private static function _processResult($class,$function,$result) {
            # Käsittely luokan ja funktion perusteella
            switch ($class) {
                case "Login":
                    switch ($function) {
                        case "doLogin":
                            if ($result["code"] == 0) {
                                $_SESSION[self::SESSIONID] = $result["data"];
                            }
                            break;
                       
                        case "doLogout":
                            if ($result["code"] == 0) {
                                unset($_SESSION[self::SESSIONID],$_SESSION[self::VIEW]);
                                session_write_close();
                            }
                            break;
                    }
                    break;
            }
           
            # Käsittely virhekoodin perusteella
            switch ($result["code"]) {
                case 10:
                    switch ($result["reasonCode"]) {
                        # Session vanhentunut tai puuttuu
                        case 60:
                            unset($_SESSION[self::SESSIONID],$_SESSION[self::VIEW]);
                            session_write_close();
                            break;
                    }
                    break;
           }
           
           return $result;
        }
        
        /**
         * Funktio lähettää kutsun sovelluksen rajapintaan.
         *
         * @param   string  $class      Kutsuttava luokka
         * @param   string  $function   Kutsuttava funktio
         * @param   array   $data       Data kutsuun (vapaaehtoinen)
         * @return  array
         */
        public static function call($class,$function,$data = array()) {           
            $result = array(
                "code"           => 9999, # 9999 = API call failed!
                "reasonCode"     => null,
                "reasonKey"      => null,
                "keyDesc"        => null,
                "text"           => "API call failed!",
                "data"           => null
            );
            
            # Luodaan URL
            $url = self::_getAPIUrl().
                "/".
                $class.
                "/".
                $function;
                    
            
            # Kutsun data
            $dataStr = "";
            if (is_array($data)) {
                $dataStr = json_encode($data);
            }
            
            # Luodaan HTTP optiot
            $opts = array(
                "http" => array(                
                    "content"   => $dataStr,
                    "header"    => "Content-type: application/json",
                    "method"    => "POST"
                )            
            );
           
            # SSL optiot
            if (mb_substr(mb_strtolower($url),0,5) == "https") {
                $opts["ssl"] = array(                    
                    "cafile"                => config("ssl","cafile"),
                    "ciphers"               => "HIGH:!SSLv2:!SSLv3",
                    "disable_compression"   => true,
                    "verify_peer"           => true
                );
            }
           
            # Lisätään sessionid mukaan kutsuun
            $logged = self::logged();
            if ($logged) {
                $opts["http"]["header"] .= "\nx-sessionid: ".
                    $logged;
            }
            
            $context = stream_context_create($opts);
            
            # Kutsu rajapintaa
            $return = file_get_contents($url,false,$context);
            if ($return) {
                $tmp = json_decode($return,true);
                if (is_array($tmp)) {
                    $result = self::_processResult($class,$function,$tmp);
                }
            }
            
            return $result;
        }
        
        /**
         * Palauttaa listan harjoituksista/liikkeistä.
         *
         * @return  array
         */
        public static function exerciseGetList() {
            static $result = array();
            
            if (empty($result)) {
                $result = self::call("Exercise","getList")["data"];
            }
            
            return $result;
        }
        
        /**
         * Palauttaa listan käytettävissä olevista lihasryhmistä.
         *
         * @return  array
         */
        public static function exerciseGetMuscleGroupList() {
            static $result = array();
            
            if (empty($result)) {
                $result = self::call("Exercise","getMuscleGroupList")["data"];
            }
            
            return $result;
        }
        
        /**
         * Palauttaa sessionid:n jos käyttäjä on kirjautunut palveluun, muussa
         * tapauksessa palautetaan boolean false.
         * 
         * @return  mixed
         */
        public static function logged() {
            $result = false;
            
            if (isset($_SESSION[self::SESSIONID])) {
                $result = $_SESSION[self::SESSIONID];
            }
            
            return $result;
        }
        
        /**
         * Palauttaa listan harjoituspaikoista.
         *
         * @return  array
         */
        public static function locationGetList() {
            return self::call("Location","getList")["data"];
        }
        
        /**
         * Päivittää käyttäjän kirjautumisen järjestelmän rajapintaan.
         *
         * @return  bool
         */
        public static function loginRefreshLogin() {
            if (self::call("Login","refreshLogin")["code"] == 0) {
                return true;
            } else {
                return false;
            }
        }
        
        /**
         * Hakee yksittäisen harjoituspohjan.
         *
         * @param   array   $data   Hakuparametrit (hashid)
         * @return  array
         */
        public static function templateLoad($data) {
            return self::call("Template","load",$data)["data"];
        }
        
        /**
         * Hakee harjoituspohjia.
         *
         * @param   array   $data   Hakuparametrit
         * @return  array
         */
        public static function templateSearch($data) {
            return self::call("Template","search",$data)["data"];
        }
        
        /**
         * Hakee yksittäisen harjoitusohjelman.
         *
         * @param   array   $data   Hakuparametrit (hashid)
         * @return  array
         */
        public static function trainingProgramLoad($data) {
            return self::call("TrainingProgram","load",$data)["data"];
        }
        
        /**
         * Hakee päivän harjoitusohjelmat/harjoituspohjat.
         *
         * @param   array   $data   Hakuparametrit
         * @return  array
         */
        public static function trainingProgramSchedule($data) {
            return self::call("TrainingProgram","schedule",$data)["data"];
        }
        
        /**
         * Hakee harjoitusohjelmia.
         *
         * @param   array   $data   Hakuparametrit
         * @return  array
         */
        public static function trainingProgramSearch($data) {
            return self::call("TrainingProgram","search",$data)["data"];
        }
        
        /**
         * Palauttaa listan aikahyöhykkeistä.
         *
         * @return  array
         */
        public static function timeZoneGetList() {
            static $result = array();
            
            if (empty($result)) {
                $result = self::call("TimeZone","getList")["data"];
            }
            
            return $result;
        }
        
        /**
         * Hakee käyttäjän painotiedot.
         *
         * @param   array   $data   Hakuparametrit
         * @return  array
         */
        public static function userGetUserWeight($data) {
            return self::call("User","getUserWeight",$data)["data"];
        }
        
        /**
         * Palauttaa kirjautuneen käyttäjän tiedot.
         *
         * @return  array
         */
        public static function userLoad() {
            return self::call("User","load")["data"];
        }
        
        /**
         * Hakee yksittäisen harjoituksen.
         *
         * @param   array   $data   Hakuparametrit (hashid)
         * @return  array
         */
        public static function workoutLoad($data) {
            return self::call("Workout","load",$data)["data"];
        }
        
        /**
         * Hakee harjoituksia.
         *
         * @param   array   $data   Hakuparametrit
         * @return  array
         */
        public static function workoutSearch($data) {
            return self::call("Workout","search",$data)["data"];
        }
        
        /**
         * Hakee yhden toiston maksimin kehityksen.
         *
         * @param   array   $data   Hakuparametrit
         * @return  array
         */
        public static function workoutOneRepMax($data) {
            return self::call("Workout","oneRepMax",$data)["data"];
        }
    }